package tge

import (
	"time"

	"sync"
	"runtime/debug"
)

// 模块接口声明
// 游戏逻辑使用模块来组织
type Module interface {
	Init()	// 初始化

	// 运行模块，注意这是一个非阻塞调用，如果有需要则使用 goroutine 去启用模块的主循环
	// cliseSig 是一个退出信号
	Run(closeSig chan bool)
	Destroy()	// 销毁
}


type module struct {
	m 	Module
	closeSig chan bool
	wg       sync.WaitGroup
}

var mods []*module

// 注册模块
func RegisterModule(m Module) {
	mi := new(module)
	mi.m = m
	mi.closeSig = make(chan bool, 1)

	mods = append(mods, mi)
}

// 初始化并执行模块
func InitModule() {
	for _, m := range mods {
		m.m.Init()
	}
	for _, m := range mods {
		m.wg.Add(1)
		go runModule(m)
	}
}

// 销毁模块
func DestroyModule() {
	for i := len(mods) - 1; i >= 0; i-- {
		// 增加模块退出的超时控制
		done := make(chan struct{}, 1)
		m := mods[i]
		go func() {
			m.closeSig <- true
			m.wg.Wait()
			destroyModule(m)
			done <- struct{} {}
		} ()
		select {
		case <- time.After(30 * time.Second):
			logger.Println("Module close time out", m)
			break
		case <- done:
			break
		}
	}
}

func runModule(m *module) {
	defer func() {
		if err := recover(); err != nil {
			logger.Println("runModule", err, string(debug.Stack()))
		}
	}()
	defer m.wg.Done()
	m.m.Run(m.closeSig)
}

func destroyModule(m *module) {
	defer func() {
		if err := recover(); err != nil {
			logger.Println("destroyModule", err, string(debug.Stack()))
		}
	}()

	m.m.Destroy()
}